package com.gaofans.nrpc.server.service;

import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author GaoFans
 */
public class ServiceBinder {

    private final Map<String,ServiceHandler> handlerMap = new ConcurrentHashMap<>();

    public <T> void register(Class<T> serviceClass, T service){
        Objects.requireNonNull(serviceClass);
        Objects.requireNonNull(service);
        handlerMap.put(serviceClass.getName(),getProxyHandler(serviceClass,service));
    }

    public ServiceHandler unRegister(String serviceClassName){
        Objects.requireNonNull(serviceClassName);
        return handlerMap.remove(serviceClassName);
    }

    public ServiceHandler get(String serviceClassName){
        Objects.requireNonNull(serviceClassName);
        return handlerMap.get(serviceClassName);
    }

    private <T> ServiceHandler getProxyHandler(Class<T> clazz, T service) {
        String handlerClassName = clazz.getName() + "GenServiceHandler";
        Class<?> handlerClass = loadClass(handlerClassName, clazz);
        Constructor<?> constructor = getConstructor(handlerClass, clazz);
        Object instance = createInstance(constructor, service);
        return (ServiceHandler)instance;
    }

    private static Class<?> loadClass(String name, Class<?> origin) {
        try {
            return origin.getClassLoader().loadClass(name);
        } catch (ClassNotFoundException var3) {
            throw new IllegalStateException("Cannot find proxyClass: " + name, var3);
        }
    }

    private static Constructor<?> getConstructor(Class<?> clazz, Class<?>... types) {
        try {
            return clazz.getDeclaredConstructor(types);
        } catch (NoSuchMethodException var3) {
            throw new IllegalStateException("Cannot find constructor on: " + clazz.getName(), var3);
        }
    }

    private static Object createInstance(Constructor<?> constructor, Object... args) {
        try {
            return constructor.newInstance(args);
        } catch (Exception var3) {
            throw new IllegalStateException("Failed to call constructor on", var3);
        }
    }
}
